package com.xlinur.moviegrabber;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;
import org.htmlcleaner.XPatherException;

public class Grabber {
	protected static final String SEPARATOR = ","; 
	protected String test = "test";
	protected String mUriSearch;
	protected String mUriItem;
	protected String mAgent;
	protected String mEncoding = "";
	protected String mPrefix;
	protected String mXpathListItem; 
	protected Map<String, String> mXpathItem;
	protected HtmlCleaner mCleaner;
	
	/*
	 * Constructor
	 */
	public Grabber(){
		mAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; ru; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10";
		mCleaner = new HtmlCleaner();
		CleanerProperties props = mCleaner.getProperties();
		props.setAllowHtmlInsideAttributes(true);
		props.setAllowMultiWordAttributes(true);
		props.setRecognizeUnicodeChars(true);
		props.setOmitComments(true);
		props.setTranslateSpecialEntities(true);
	}
	
	/*
	 * Return Content from URI
	 */
	protected String getUriContent(String uri) {
		String result = null;
		HttpClient client = new DefaultHttpClient();
		HttpGet request = new HttpGet();
		StringBuffer sb = null;
		Boolean flag = false;
		try {
			request.setURI(new URI(uri));
			request.setHeader("User-Agent", this.mAgent);
			HttpResponse response = client.execute(request);
			BufferedReader in = new BufferedReader(new InputStreamReader(
					response.getEntity().getContent(), this.mEncoding));
			sb = new StringBuffer("");
			String line = "";
			String NL = System.getProperty("line.separator");
			while ((line = in.readLine()) != null) {
				sb.append(line + NL);
			}
			in.close();
			flag = true;
		} catch (ClientProtocolException e) {
		} catch (IOException e) {
		} catch (URISyntaxException e) {
		}
		if (flag) {
			result = sb.toString();
			if (result.equals("")) {
				result = null;
			}
		}
		return result;
	}
	
	/*
	 * Return Id Movie from URI
	 */
	private String getId(String uri){
		String id = uri.substring(0,uri.length()-1);
		id = id.substring(id.lastIndexOf("/")+1);
		return id;
	}
	/*
	 * Item details length format to minutes
	 */
	protected String formatLength(String str){
		return str;
	}
	
	/*
	 * Return item info from string
	 */
	private HashMap<String,String> getInfoFromString(String keyStr, String value){
		HashMap<String,String> result = new HashMap<String,String>();
		String[] keyArr = keyStr.split("!");
		int count = keyArr.length;
		if (count>2) {
			String[] keys = keyArr[1].split(",");
			String separator = keyArr[2];
			Boolean backDirection = keyArr[2].startsWith("~");
			if (backDirection) {
				separator = separator.substring(1);
			}
			int keysCount = keys.length;
			String[] values = new String[keysCount];
			String[] valuesSep = value.split(separator);
			
			int vSepCount =  valuesSep.length;
			int delta = vSepCount-keysCount; 
			if (backDirection){
				for (int i=0; i<vSepCount; i++){
					if (i>delta) {
						values[i-delta] = valuesSep[i];
					} else {
						if (values[0]!=null){
							values[0] += separator;
						} else {
							values[0]="";
						}
						values[0] += valuesSep[i];
					}
				}
			} else {
				for (int i=0; i<vSepCount; i++){
					if (i<keysCount) {
						values[i] = valuesSep[i];
					} else {
						if (values[keysCount-1]!=null){
							values[keysCount-1] += separator;
						} else {
							values[keysCount-1] = "";
						}
						values[keysCount-1] += valuesSep[i];
					}
				}
			}
			
			for (int i=0; i<keysCount; i++){
				if (values[i]==null){
					values[i] = "";
				}
				if (keyArr[3+i]!=null && !keyArr[3+i].equals("")) {
					values[i]=values[i].replaceAll(keyArr[3+i], "");
				}
				values[i] = values[i].trim();
				if ("length".equals(keys[i])){
					values[i]=this.formatLength(values[i]);
				}
				result.put(keys[i],values[i]);
			}
		}
		return result;
	}
	
	/*
	 * Return Movies list for search string
	 */
	public HashMap<String, String> getList(String searchString){
		Boolean flag = false;
		String listStr = null;
		HashMap<String, String> result = new HashMap<String,String>();
		try {
			listStr = this.getUriContent(this.mUriSearch.replace("{1}",
					URLEncoder.encode(searchString,this.mEncoding)));
		} catch (UnsupportedEncodingException e1) {
		}
		if (listStr != null) {
			TagNode node = null;
			Object[] list = null;
			try {
				node = mCleaner.clean(listStr);
				list = node.evaluateXPath(this.mXpathListItem);
				flag = true;
			} catch (IOException e) {
			} catch (XPatherException e) {
			}
			int count = list.length;
			if (flag && count > 0) {
				for (int i = 0; i < count; i++) {
					node = (TagNode) list[i];
					result.put(this.getId(node.getAttributeByName("href")), node.getText().toString());
				}
			}
		}
		if (flag){
			return result;
		} else {
			return null;
		}
	}
	
	/*
	 * Return Movie for Id
	 */
	public HashMap<String, String> getItem(String id){
		HashMap<String, String> result = new HashMap<String,String>();
		Boolean flag = false;
		String movieStr = this.getUriContent(this.mUriItem.replace("{1}",id));
		if (movieStr != null) {
			result.put("ext_id", this.mPrefix+id);
			TagNode info = null;
			try {
				info = this.mCleaner.clean(movieStr);
				Set<String> keys = this.mXpathItem.keySet();
				Iterator<String> it = keys.iterator();
				while(it.hasNext()){
					try {
						String key = (String) it.next();
						Object[] item = info.evaluateXPath(this.mXpathItem.get(key));
						int count = item.length;
						if (count>0 && item[0]!=null){
							if (count==1){
								TagNode node = (TagNode) item[0];
								String value = node.getText().toString().trim();
								if (key.startsWith("!")){
									result.putAll(this.getInfoFromString(key,value));
								} else {
									if ("length".equals(key)){
										value=this.formatLength(value);
									}
									result.put(key, value);
								}
							} else {
								String value="";
								for (int i=0; i<count; i++){
									TagNode node = (TagNode) item[i];
									if (i>0) {
										value += SEPARATOR+" ";	
									}
									value += node.getText().toString().trim();
								}
								result.put(key, value);
							}
						}
					} catch (XPatherException e) {
					}
				}
				flag = true;
			} catch (IOException e) {
			}
		}
		if (flag){
			return result;
		} else {
			return null;
		}
	}
}